package service

import (
	"context"
	"errors"
	"github.com/google/uuid"
	_ "github.com/google/uuid"
	"saleforce/sf-backend-user/bootstrap"
	"saleforce/sf-backend-user/config"
	"saleforce/sf-backend-user/constant"
	"saleforce/sf-backend-user/model"
	bs "saleforce/sf-common/protoc/backend-user"
	"saleforce/sf-common/utils"
	"time"
)

type LoginService struct {
	bs.UnimplementedLoginServiceServer
}

// Login 登录方法
func (l LoginService) Login(c context.Context, p *bs.LoginParam) (*bs.LoginResp, error) {
	bootstrap.InitAll()
	username := p.Username
	password := p.Password
	lang := p.Lang
	if lang == "" {
		lang = "cn"
	}
	if username == "" {
		return nil, errors.New("Username cannot be empty")
	}
	if password == "" {
		return nil, errors.New("Password cannot be empty")
	}
	password = utils.Md5(password)
	user, err := model.User{}.GetByUserName(username)
	if err != nil {
		return nil, errors.New(err.Error())
	}
	if p.Ip == "" {
		return nil, errors.New("IP cannot be empty")
	}
	if user == nil {
		return nil, errors.New("User is not exist")
	}
	if user.Password != password {
		return nil, errors.New("Wrong password")
	}
	if user.Status != 1 {
		return nil, errors.New("User status abnormal")
	}
	user_p := bs.User{
		Id:       user.Id,
		Username: user.Username,
		Nickname: user.Nickname,
		Status:   user.Status,
		UserType: user.UserType,
		RoleId:   user.RoleId,
	}
	role, _ := model.Role{}.GetById(user.RoleId)
	role_p := bs.Role{
		Id:       role.Id,
		RoleName: role.RoleName,
		Status:   role.Status,
		Menus:    role.Menus,
		IsSys:    role.IsSys,
	}
	relations, _ := model.DepartmentExtModel{}.GetRelationsByUserId(user.Id)
	depIds := []int64{}
	for _, relation := range relations {
		depIds = append(depIds, relation.DepId)
	}
	depsInModel, _ := model.DepartmentModel{}.ListByIds(depIds)
	depsMap := make(map[int64]model.DepartmentModel)
	for _, dep := range depsInModel {
		depsMap[dep.Id] = dep
	}
	depsRes := []*bs.Department{}
	for _, relation := range relations {
		dep := depsMap[relation.DepId]
		unit := bs.Department{
			Id:          dep.Id,
			ExtId:       relation.Id,
			Name:        dep.Name,
			Status:      dep.Status,
			ParentId:    dep.ParentId,
			WorkNo:      relation.WorkNo,
			Position:    relation.Position,
			Description: relation.Description,
		}
		depsRes = append(depsRes, &unit)
	}
	menuIds := role.Menus
	slice, _ := utils.StringToIntSlice[int64](menuIds)
	menusInModel, _ := model.MenuModel{}.ListByIds(slice)
	menusRes := []*bs.Menu{}
	for _, m := range menusInModel {
		u := bs.Menu{
			Id:         m.Id,
			Name:       m.Name,
			Status:     m.Status,
			MenuType:   m.MenuType,
			IsShow:     m.IsShow,
			ParentId:   m.ParentId,
			ApiUrl:     m.ApiUrl,
			ModuleLink: m.ModuleLink,
			Icon:       m.Icon,
			Created:    utils.ConvertTimeToTimestamp(m.Created),
			Updated:    utils.ConvertTimeToTimestamp(m.Updated),
		}
		menusRes = append(menusRes, &u)
	}
	exp := time.Now().Add(time.Hour * 2).Unix() //后期从配置项获取

	resp := bs.LoginResp{
		User:        &user_p,
		Role:        &role_p,
		Departments: depsRes,
		Lang:        lang,
		LoginTime:   time.Now().Unix(),
		Menus:       menusRes,
		Exp:         exp,
		LoginIp:     p.Ip,
	}
	jwt, err := utils.GenerateJWT(resp, config.JwtConf.Secret)
	if err != nil {
		return nil, errors.New(err.Error())
	}
	u := uuid.New().String()
	constant.Rds.Append(c, "LG-"+u, jwt)
	resp.Token = "LG-" + u
	return &resp, nil
}

// IsLogin 判断是否登录
func (l LoginService) IsLogin(c context.Context, p *bs.IsLoginParam) (*bs.LoginResp, error) {
	bootstrap.InitAll()
	token := p.Token
	lang := p.Lang
	if lang == "" {
		lang = "cn"
	}
	if token == "" {
		return nil, errors.New("Token cannot be empty")
	}
	get := constant.Rds.Get(c, "LG-"+token)
	if get.Err() != nil {
		return nil, errors.New("Invalid token")
	}
	jwtStr, err := get.Result()
	if err != nil {
		return nil, errors.New("Invalid token")
	}
	return l.checkToken(jwtStr, lang)
}

func (l LoginService) checkToken(jwtStr string, lang string) (*bs.LoginResp, error) {
	bootstrap.InitAll()
	jwt, err := l.getJwt(jwtStr)
	if err != nil {
		return nil, errors.New(err.Error())
	}
	expireTime := time.Unix(jwt.Exp, 0)
	now := time.Now()
	if expireTime.Before(now) {
		return nil, errors.New("Please log in to operate")
	}
	//更新过期时间
	jwt.Exp = time.Now().Add(time.Hour * 2).Unix() //后期从配置项获取
	//jwt.Token = ""
	jwt.Lang = lang
	jwtStr, err = utils.GenerateJWT(jwt, config.JwtConf.Secret)
	if err != nil {
		return nil, errors.New(err.Error())
	}
	jwt.Token = jwtStr
	c := context.Background()
	constant.Rds.Append(c, jwt.Token, jwtStr)
	return jwt, nil
}

func (l LoginService) getJwt(jwtStr string) (*bs.LoginResp, error) {
	return utils.ParseJWT[bs.LoginResp](jwtStr, config.JwtConf.Secret)
}

func (l LoginService) Logout(c context.Context, p *bs.TokenParam) (*bs.LogoutResp, error) {
	bootstrap.InitAll()
	token := p.GetToken()
	get := constant.Rds.Get(c, token)
	if get.Err() != nil {
		constant.Rds.Del(c, token)
		return nil, errors.New("quit unexpectedly")
	}
	jwtStr, err := get.Result()
	if err != nil {
		return nil, err
	}
	jwt, err := l.getJwt(jwtStr)
	if err != nil {
		return nil, err
	}
	constant.Rds.Del(c, token)
	if result, err := constant.Rds.Exists(c, token).Result(); err == nil && result <= 0 {
		res := new(bs.LogoutResp)
		res.IsLogout = true
		res.LogoutTime = time.Now().Unix()
		res.LoginResp = jwt
		return res, nil
	} else {
		return nil, err
	}

}
